본문 바로가기

WebGL

WebGL Fundamentals > Fundamentals : vertex shader를 통해 클립 공간으로 변환, uniform을 사용하여 캔버스 해상도와 색상 설정, 좌측상단 모서리가 (0, 0)이 되도록 y좌표 반전

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

 

 

RandomRectangles

이번 실습에서 복습할 포인트.

  • vertex shader를 통해 클립 공간으로 변환
  • uniform을 사용하여 캔버스 해상도와 색상 설정
  • 좌측상단 모서리가 (0, 0)이 되도록 y좌표 반전

 

1. 픽셀좌표로 데이터를 넘기기 위해 클립 공간으로 변환하는 vertex shader 작성.

WebGL은 래스터화 API에 불과하기 때문에 3D를 원한다면,

3D를 클립 공간으로 변환하는 shader를 작성해야 한다.

 

2D의 경우 클립 공간보다 픽셀로 작업하는 게 좋으니,

위치를 픽셀로 제공하고 클립 공간으로 변환할 수 있도록, 

기존 작성한 vertex shader를 바꿔준다.

 

<script id="vertex-shader-2d" type="notjs">
 
  //x, y만 사용하기 때문에 vec2로 수정
  attribute vec2 a_position;
 
  //캔버스 해상도를 설정하기 위해 uniform 추가
  uniform vec2 u_resolution;
 
  void main() {
    // 위치를 픽셀에서 0.0과 1.0사이로 변환
    vec2 zeroToOne = a_position / u_resolution;
 
    // 0->1에서 0->2로 변환
    vec2 zeroToTwo = zeroToOne * 2.0;
 
    // 0->2에서 -1->+1로 변환 (클립 공간)
    vec2 clipSpace = zeroToTwo - 1.0;
 
    gl_Position = vec4(clipSpace, 0, 1);
  }
 
</script>

 

 

u_resolution이라는 uniform을 추가했기 때문에 uniform의 위치를 찾는 작업을 진행해야 한다.

 

var resolutionUniformLocation = gl.getUniformLocation(program, "u_resolution");

 

u_resolution을 캔버스의 해상도로 설정함으로써, 

shader는 픽셀 좌표로 제공한 positionBuffer에 넣은 위치를 가져와 클립 공간으로 변환한다.

 

2. program을 설정한 뒤 uniform으로 해상도 설정

gl.useProgram은 gl.bindBuffer처럼 현재 program을 설정한다.

gl.useProgram으로 program이 설정된 후 호출되는 모든 gl.uniformXXX 함수는 현재 설정된 프로그램의 유니폼을 설정하게 된다.

 

gl.useProgram(program);
 
//...
 
// 해상도 설정
gl.uniform2f(resolutionUniformLocation, gl.canvas.width, gl.canvas.height);

 

canvas의 너비와 높이를 넘겨줘서 해상도를 설정한다.

 

3. 사각형을 그리려면 2개의 삼각형을 그려야 하고 그러기 위해 vertex shader를 6번 호출하도록 수정한다.

// 그리기
var primitiveType = gl.TRIANGLES;
var offset = 0;
// 6번 호출
var count = 6;
gl.drawArrays(primitiveType, offset, count);

 

4. 2D 그래픽 API에서 더 전통적으로 사용되는 좌측상단 모서리가 (0, 0)이 되도록 조정.

WebGL은 양수 Y를 위쪽으로, 음수 Y를 아래쪽으로 간주한다.

클립 공간에서 좌측 하단 모서리는 -1,-1이 된다.

이를 2D 그래픽 API에서 더 전통적으로 사용되는 좌측 상단 모서리가 되도록 클립 공간 y좌표를 뒤집는다.

 

gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);

 

5. fragment shader가 색상 정보를 담는 uniform 입력을 가져오록 설정.

 

<script id="fragment-shader-2d" type="notjs">

  precision mediump float;
  // 색상 정보를 입력받기 위해 uniform 추가 
  uniform vec4 u_color;
 
  void main() {
    // gl_FragColor는 fragment shader의 설정을 담당하는 특수 변수
    // 색상 정보 uniform을 대입
    gl_FragColor = u_color;
  }

</script>

 

6. Random한 위치와 색상으로 여러 개의 사각형을 그리는 코드 추가.

 

// u_color라는 uniform을 fragment shader에 추가했기 때문에 uniform의 위치를 찾는 작업을 진행
var colorUniformLocation = gl.getUniformLocation(program, "u_color");

//...
 
// 임의의 색상으로 임의의 사각형 50개 그리기
for (var ii = 0; ii < 50; ++ii) {
  // 임의의 사각형 설정
  // 초기화 과정에서 수행했던 gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
  // ARRAY_BUFFER 바인드 포인트에 마지막으로 바인딩한 것이므로 `positionBuffer`에 작성된다.  
  setRectangle(
    gl,
    randomInt(300),
    randomInt(300),
    randomInt(300),
    randomInt(300)
  );
 
  // 임의의 색상 설정
  gl.uniform4f(
    colorUniformLocation,
    Math.random(),
    Math.random(),
    Math.random(),
    1
  );
 
  // 사각형 그리기
  gl.drawArrays(gl.TRIANGLES, 0, 6);
}
 
// 0부터 -1사이의 임의의 정수 반환
function randomInt(range) {
  //Math.floor() : 소수점 이하를 버림한다.
  return Math.floor(Math.random() * range);
}
 
// 사각형을 정의한 값들로 버퍼 채우기
function setRectangle(gl, x, y, width, height) {
  var x1 = x;
  var x2 = x + width;
  var y1 = y;
  var y2 = y + height;
 
  // 참고: gl.bufferData(gl.ARRAY_BUFFER, ...)는 `ARRAY_BUFFER` 바인드 포인트에 바인딩된 버퍼에 영향을 준다.
  // 버퍼가 두 개 이상이라면 원하는 버퍼를 `ARRAY_BUFFER`에 먼저 바인딩해야 한다.
  gl.bufferData(
    gl.ARRAY_BUFFER,
    new Float32Array([
      x1, y1,
      x2, y1,
      x1, y2,
      x1, y2,
      x2, y1,
      x2, y2
    ]),
    gl.STATIC_DRAW
  );
}

 

초기화 과정에서 수행했던 gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);로 버퍼가 바인딩 되어 있다.
그래서 사각형의 좌표를 설정할 때,

gl.bufferData 메서드 파라미터로  new Float32Array를 넘겨주면 버퍼가 갱신되어 shader로 데이터를 넘겨줄 수 있다.

 

버퍼가 2개 이상이고 교체해줄 필요가 있다면 gl.bufferData로 버퍼에 데이터를 넘겨주기 전에 원하는 버퍼로 바인딩부터 해야한다.

 

 

 

 

 

 

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

 

WebGL_Fundamentals

 

myoungmin.github.io