[토이] Material wave

EEuglena·2023년 11월 10일
0

토이 프로젝트

목록 보기
5/6

아이디어

크게 두 가지 목표가 있었다. 일단 canvas를 좀 활용해 보고 싶었고, 불멍, 물멍처럼 가만히 보고 있을 수 있는 애니메이션을 만들어 보고 싶었다. 그런데 태생이 이과라 그런지 온갖 파동함수들이 떠올랐고 물질파 같은 걸 만들면 나름 괜찮을 것 같았다. 생각해보니 리액트 로고도 원자 모형 같이 생긴 것이 빙글빙글 돌아가는데 물질파라고 안 될 거 있나?

구현 1. 파동함수 개형

canvas에 도형을 그리려면 좌표를 전달해 줘야 하는데, 그러기 위해서는 일단 파동함수를 만들어야 한다. 일단 선형 사인파부터 차례대로 생각해 보자.

y=Asin(X(x)T(t))y = A\sin(X(x) - T(t))

부호나 위상을 무시하고 간단하게 개형만 적으면 위와 같다. 이를 원형으로 그리려면 방위좌표계로 변환하는 게 다루기 쉬울 것이다. 그러니 기호를 조금 바꿔서 다음과 같이 적도록 하자.

r(θ,t)=Asin(X(θ)T(t))r(\theta,t) = A\sin(X(\theta) - T(t))

원주를 따라서 그려 나간다고 하면 각도에 따른 반지름을 아래와 같이 나타낼 수 있다.

R(θ)=R0+r(θ,t)R(\theta)=R_0 + r(\theta,t)

다만 실제로 canvas에 그릴 때는 직교좌표계를 이용해야 하므로 변환과정을 한 번 거쳐야 한다. 이때 일반적인 직교좌표계와 canvas의 좌표는 축이 조금 다른데, y축이 아래로 갈수록 커지기 때문에 부호를 반대로 넣어야 한다.

x=R(θ)cosθy=R(θ)sinθx = R(\theta)\cos\theta \\ y = -R(\theta)\sin\theta

이를 코드로 옮기면 다음과 같다.

for (let rad = 0; rad < Math.PI * 2; rad += Math.PI * 0.02) {
  const radius =
        RADIUS +
        AMPLITUDE *
        Math.sin(n * rad + t / PERIOD + (2 * m * Math.PI) / n);
  ctx.lineTo(
    CENTER[0] + radius * Math.cos(rad),
    CENTER[1] + radius * Math.sin(rad)
  );
}

구현 2. 시각화

파동 자체는 완성했지만 몇 가지 시각화 요소를 더 추가하고 싶었다. 그래서 y축 방향으로 파동을 따라 움직이는 점과, 점의 높이를 표시하는 선을 각각 표시하는 기능을 구현했다. 이미 파동함수는 완성했으니 특정 위상에서 점만 추가로 그려주면 된다. -y축 방향에 점이 있도록 하는 것이 제일 보기 좋아서 θ=π2\theta=-{\pi\over2}에 점을 표시하는 것으로 정했고, 같은 높이에 화면을 가로지르는 선을 그리도록 했다.

const pointer = [
  CENTER[0],
  CENTER[1] - RADIUS - AMPLITUDE * Math.sin(-Math.PI / 2 + t / PERIOD),
];

if (drawPointer) {
  ctx.beginPath();
  ctx.arc(pointer[0], pointer[1], 5, 0, Math.PI * 2, true);
  ctx.closePath();
  ctx.fillStyle = "red";
  ctx.fill();
}

if (drawLine) {
  ctx.beginPath();
  ctx.moveTo(0, pointer[1]);
  ctx.lineTo(400, pointer[1]);
  ctx.closePath();
  ctx.stroke();
}

구현 3. 파동함수 추가

원하는 요소는 다 구현했지만 왠지 피젯 스피너가 돌아가는 것 같은 모습이라 그렇게 보기 좋지는 않았다. 그래서 파수에 따라 2πm2\pi\over m씩 위상이 차이나는 함수를 여러 개 그려보기로 했다. 파동함수의 위상만 조금씩 차이나게 하면 되므로 코드는 거의 달라지지 않았고, 함수별로 동일한 각도에서 점들을 동시에 볼 수 있도록 하는 시각화 요소를 추가로 만들었다. 이 기능을 추가하면서 사용자가 파수를 변화시킬 수 있도록 증감 버튼을 페이지에 배치해서 파수에 따라 함수가 달라지는 모습도 볼 수 있도록 했다. 단, 파수가 1 미만으로 내려가거나 너무 커지면 렌더링이 불가능하므로 1 이상 12 이하의 구간에서만 변화하도록 했다.

결과물

사실 버튼이라고 넣은 요소가 버튼처럼 보이지 않기 때문에 UX 측면에서는 좋지 않은 결과물이다. 하지만 최대한 주변 요소를 단순하게 만들어 키비주얼에 집중하도록 만들기 위해 의도적으로 버튼을 단순화시켜 표현했다. 색도 흑백 단색으로 구성하였고 포인터 한 점만 빨간색으로 만들어 페이지 전체에서 포인터에 시선이 집중되도록 했다. 다만 이 상태에서는 버튼을 인식하는 게 정말 어려울 것 같아서 커서는 포인터 모양으로 바뀌도록 css를 약간 수정해줬다.

코드는 깃허브에

깃허브 링크

0개의 댓글