이전 글 : [WebGL2-My Cosmos-02] Canvas 공통 설정
[WebGL2-My Cosmos-02] Canvas 공통 설정
이전 글 : [WebGL2-My Cosmos-01] 프로젝트 세팅 [WebGL2-My Cosmos-01] 프로젝트 세팅프로젝트 아이디어WebGL2로 웹에서 3D 그래픽을 구현하고자 내가 좋아하는 우주를 배경으로 시작하고 싶었다.입력한 이
jinsk-joy.tistory.com
WebGL 설정
WebGL을 적용하는 캔버스를 관리하기 위한 CanvasGL 클래스를 생성한다.
생성자
- CanvasOption을 상속받아 기본적인 CSS 크기를 설정하고 CavasGL 클래스에서 GL의 물리적 크기를 설정한다.
- 3D 렌더링을 위해 깊이 테스트를 활성화한다. 깊이 테스트를 활성화하지 않을 경우 그려지는 순서대로 픽셀을 덮어 씌우기 때문에 원근 효과가 제대로 적용되지 않는다.
- WebGL로 애니메이션을 구현하기 위해 FPS, Interval 값을 설정하고 애니메이션을 관리하기 위한 멤버 변수를 생성한다.
class CanvasGL extends CanvasOption {
/**
* GL설정 및 애니메이션 관리
* @param {string} canvasId
*/
constructor(canvasId) {
// CanvasOption을 상속받아 사용한다.
super(canvasId);
// webgl2 context를 가져온다. 만약 없을 경우 에러를 발생시킨다.
this.gl = this.canvas.getContext("webgl2");
if (isNull(this.gl)) throwError(ERROR_MSG.NO_WEBGL2);
// 깊이 테스트 활성화
// WebGL은 기본적으로 2D 기반이므로, 3D 렌더링 시 깊이 축을 고려해야한다.
// DEPTH_TEST를 활성화하면 WebGL이 Z버퍼를 사용하여
// 화면에서 가까운 객체가 먼 객체보다 앞에 그려지도록 처리한다.
this.gl.enable(this.gl.DEPTH_TEST);
// CanvasOption 사이즈 설정을 바탕으로 WebGL의 물리적 크기 설정
this.setCanvasGLSize();
// 애니메이션 관련 설정
this.fps = ANIMATION.FPS;
this.interval = 1000 / this.fps;
this.animationId = null;
this.animationFunc = null;
}
생략...
}
GL 사이즈 설정
- 생성자에서 실행될 WebGL의 물리적 크기를 설정하기 위한 메서드를 따로 작성하였다.
- WebGL의 기본 좌표 공간 즉 클립 공간은 (-1 ~ 1)의 범위를 가지며 픽셀 단위의 크기가 아니다. 좌상단이 (-1, 1), 정가운데가 (0, 0) 우상단이 (1, 1)이라 기존의 좌표체계와 다르다.
- viewport를 설정하면 클립 공간을 실제 우리가 사용하는 좌표체계인 픽셀 좌표계로 변환하여 실제 화면 크기에 맞게 설정할 수 있게 된다. 이 과정에 없으면 WebGL이 캔버스의 일부만 사용하거나 왜곡된 화면을 출력할 수 있다.
setCanvasGLSize() {
// 부모 클래스인 CanvasOption의 메서드를 실행해 CSS 크기를 설정한다.
// 이 과정에서 canvas 태그의 width, height와 DPR의 값이 결정된다.
this.initCanvasOptionSizeVars();
// CSS 크기에 DPR을 곱하여 WebGL의 물리적 크기(실제 랜더링 해상도)를 설정한다.
this.gl.canvas.width = this.canvasCssWidth * this.dpr;
this.gl.canvas.height = this.canvasCssHeight * this.dpr;
// WebGL의 viewport 크기를 물리적 크기로 설정하여 캔버스 전체 영역이 정상적으로 랜더링되도록 한다.
this.gl.viewport(0, 0, this.gl.canvas.width, this.gl.canvas.height);
// 카메라 설정 시 필요한 종횡비를 계산하여 설정한다. (투영행렬에 사용)
this.aspect = this.gl.canvas.width / this.gl.canvas.height;
}
애니메이션 공통 설정
- 2개의 GL 화면에서 애니메이션을 사용하고 있으므로 공통부분을 설정하는 메서드를 만들어 재사용성을 높였다.
- this.animationFunc은 각 화면에서 실행될 개별 애니메이션 로직을 저장하고 실행하는 역할을 한다.
- 애니메이션 속도는 초당 60 프레임(FPS)을 유지되며 1 프레임의 지속 시간은 약 16.67ms(1000ms / 60, interval)이다.
- 애니메이션 속도를 일정하게 유지하기 위해 delta(현재 시간과 이전 시간과의 차이)가 16.67ms를 초과한 경우 초과된 시간을 보정하여 다음 프레임이 일정한 간격으로 유지되도록 한다.
// 애니메이션 실행 메서드 (공통 뼈대)
renderAnimation() {
// 이전 프레임의 시간을 저장하는 변수
// 초기값은 currentTime이 지원되면 해당 값을 사용하고 아닐경우 performance.now를 사용한다.
let then = document.timeline?.currentTime || performance.now();
// 애니메이션 프레임을 처리하는 함수
const frame = (now) => {
// 현재 프레임과 이전 프레임의 시간차이를 계산한다.
const delta = now - then;
// 일정 시간(interval - 1000ms / 60프레임)이 경과하면 애니메이션을 갱신한다.
if (delta >= this.interval) {
// GL에서 시간단위는 주로 sec를 사용하므로 ms를 sec로 변환한다.
const uTime = now * 0.001;
// 이전 프레임의 잔상을 제거하기 위해 색상, 깊이 버퍼를 초기화한다.
this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
// 각 화면에서 개별적으로 설정한 애니메이션을 실행한다.
this.animationFunc(uTime);
// 오차를 보전해 일관된 속도를 유지한다.
then = now - (delta % this.interval);
}
// 다음 프레임을 예약하여 재귀적으로 애니메이션이 실행
this.animationId = requestAnimationFrame(frame);
};
// 애니메이션 실행 시작
this.animationId = requestAnimationFrame(frame);
}
// 애니메이션 취소 함수
cancelAnimation() {
// cancelAnimationFrame과 animationId을 사용하여 현재 실행되고 있는 애니메이션 중단
cancelAnimationFrame(this.animationId);
// 애니메이션을 취소한다음 id를 초기화 시킨다.
this.animationId = null;
}
Github 레포
GitHub - jinsk9268/my-cosmos: 나만의 우주 탐험하기
나만의 우주 탐험하기. Contribute to jinsk9268/my-cosmos development by creating an account on GitHub.
github.com
'WebGL2 > My Cosmos 프로젝트' 카테고리의 다른 글
[WebGL2-My Cosmos-02] Canvas 공통 설정 (1) | 2025.03.09 |
---|---|
[WebGL2-My Cosmos-01] 프로젝트 세팅 (0) | 2025.03.09 |