Home
프로필

원과 삼각비

💡 WebGL과 수학 공식

수학을 잘하지도, 놓고 산 지도 오래인 문과충 나... 그럼에도 WebGL 욕심은 있어서 관심을 놓지 않기로 다짐했다.

우선 기본으로 여겨지는 삼각함수부터, 밑바닥부터 다져야 한다.

💡 삼각함수와 원의 관계


"싸인과 코싸인을 이해한다는 것은 원과 삼각형의 관계를 이해하는 것과 같습니다." 위 유튜브 中

일단 어떤 원의 반지름을 빗변으로 가지는 직각 삼각형을 상상해보자. 이 삼각형은 직각 삼각형이기 때문에 삼각함수의 지배를 받는다. 이때 쉬운 계산을 위해 반지름 r의 길이를 1로 둔다. 그러면 이 원주의 특정 위치(점)에 대한 좌표를 쉽게 구해낼 수 있는데, 필요한 건 각도 세타(𝜃) 뿐이다.

여기서 삼각함수가 말해주는 것은 다음과 같다. 빗변의 길이가 1이고 각도가 𝜃일 때, 삼각형 밑변의 길이는 cos(𝜃), 높이는 sin(𝜃)이라는 것이다. 중요한 건 코사인은 x 좌표, 싸인은 y 좌표에 관여한다는 것을 이해하는 것이다. 이 둘은 각각 x 좌표, y 좌표에 대응하며 해당 원주에 접근하는 좌표값을 제공한다.

💡 Demo

우선 그리드 중심에 원점을 나타내는 공을 하나 만들어보자


var mesh = new THREE.Mesh(
new THREE.SphereGeometry(0.01, 32, 32);
new THREE.MeshNormalMaterial();
);
function addPoint(x, y, z){
var point = mesh.clone();
point.position.set(x, y, z);
scene.add(point);
return point;
}
addPoint(0, 0, 0);

만들어졌다면 이 공을 중점으로 한 가상의 원을 상상한다. 꼭 놀이동산의 대관람차처럼 말이다. 위에서 배운 삼각함수 법칙으로 그 원주에 위치하는 점들을 일일이 찍어낼 수 있다

다시 기억하면, 이때 필요한 건 오직 세타(𝜃)다. 세타를 설정하는 데는 다음이 필요한데, 부연하자면,

  • Math.PI * 2: 원 한바퀴(360도)의 radian값은 2π이다. 이를 기준으로
  • i/number: 0에서 1 사이의 값을 곱해 원의 각도를 균등하게 분할한다

그러면 반복문으로 각각의 각도(그로인해 각각의 좌표)를 가진 공을 얻을 수 있다. 후에 애니메이션을 가미하기 위해 객체로 포장하여 하나의 배열에 담아두도록 한다.


var number = 30;
var objects = [];
for (let i = 0; i < number; i++){
let theta = (i/number) * Math.PI * 2;
let x = Math.cos(theta), y = Math.sin(theta), z = 0;
let mesh = addPoint(x, y, z);
let newBall = {
mesh,
theta,
x: Math.random() / 5,
y: Math.random() / 5,
z: Math.random() / 5,
}
objects.push(newBall)
}

그러면 대관람차 모양의 배치가 완성된다.

이미지

밋밋하니 다음과 같은 애니메이션을 추가해보자.


// animation
function animation(time){
objects.forEach(function 공전(ball){
let {mesh, theta, x, y, z} = ball;
let newTheta = theta + time / 1000;
let nx = Math.cos(newTheta) + x;
let ny = Math.sin(newTheta) + y;
let nz = z;
mesh.position.set(nx, ny, nz);
});
mesh.rotation.x = time / 2000;
mesh.rotation.y = time / 1000;
renderer.render(scene, camera);
}

적용된 코드들의 효과는 이러하다

  • 새로운 세타: 시간이 갈 때마다 세타의 값에 상수를 더한다. 값(각도)을 추가하더라도 싸인과 코싸인은 일정한 파동을 그리면서 궤적을 이탈하지 않는다. 즉 원을 순환하면서 무한히 회전하는 움직임을 보이게 된다.
  • 새로운 포지션: 기존의 x, y, z 가 정적으로 고정된 위치에 있었기 때문에 Math.random() 값을 더하여 불규칙적으로 이탈하게 한다. 자유도를 부여하는 작업이고 나누기의 값으로 정도를 조정한다.


그러면 아쿠아맨이 쓸 법한 물의 고리가 완성된다. 스크린샷은 number를 30으로 두고 찍었는데 사이즈를 키울수록 좀 더 있어 보인다

이미지

Comment ?

▾ Comment

🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧