라디안 : 호의 길이가 반지름과 같게 되는 만큼의 각
디그리 : 일상에서 사용하는 각도
180 degree = (π * radian)
radian = 57.295....
부채꼴 도형에서 반지름, 중심각, 호의 길이 3가지 중에 2가지만 알면 다른 한가지는 바로 쉽게 구할 수 있다.
여러 개의 이미지를 하나의 이미지로 합쳐서 관리하는 이미지
(3D에서는 아틀라스라고도 불린다)
사용된 이미지가 많을 경우 웹 브라우저는 서버에 해당 이미지의 수만큼 요청해야만 하므로 웹 페이지의 로딩 시간이 오래 걸리게 된다.
const El = class{
constructor(){this.el = document.createElement('div')}
set class(v){this.el.className = v;}
}
let el = new El(); el.class = '클래스이름'
을 적용하면
해당 클래스를 적용시킨다.
const Face = class extends El{
constructor(w,h,x,y,z,rx,ry,rz,tx,ty){
super();
this.el.style.cssText = `
position:absolute;
width:${w}px; height:${h}px;
margin:-${h/2}px 0 0 -${w/2}px;
transform:translate3d(${x}px,${y}px,${z}px)
rotateX({rx}rad) rotateY(${ry}rad) rotateZ(${rz}rad);
background-position: -${tx}px ${ty}px;
`
}
}
const Mesh = class extends El {
constructor(l, t) {
super();
this.el.style.cssText = `
position: absolute;
left: ${l}; top: ${t};
transform-style: preserve-3d;
`;
}
add(face) {
if (!(face instanceof Face)) throw "invalid face";
this.el.appendChild(face.el);
return face;
}
};
Face 클래스에서의 결과를 합쳐주는 역할
<!DOCTYPE html>
<html lang="en">
<head>
<style>
@keyframes spin {
to {
transform: rotateY(360deg) rotateZ(360deg) rotateX(720deg);
}
}
html,
body {
height: 100%;
}
body {
perspective: 600px;
background: #404040;
}
.ani {
animation: spin 4s linear infinite;
}
.drum {
background: url("http://keithclark.co.uk/labs/css-fps/drum2.png");
}
</style>
</head>
<body>
<div></div>
</body>
<script>
// 본격적으로 드럼통을 만들어보자
const El = class {
constructor() {
this.el = document.createElement("div");
}
set class(v) {
this.el.className = v;
}
};
// El을 상속받는 Face 클래스
const Face = class extends El {
constructor(w, h, x, y, z, rx, ry, rz, tx, ty) {
super();
this.el.style.cssText = `
position: absolute;
width: ${w}px;
height: ${h}px;
margin: -${h / 2}px 0 0 -${w / 2}px;
transform: translate3d(${x}px, ${y}px, ${z}px)
rotateX(${rx}rad) rotateY(${ry}rad) rotateZ(${rz}rad);
background-position: -${tx}px ${ty}px;
backface-visibility: hidden; //⭐
`;
}
};
const Mesh = class extends El {
constructor(l, t) {
super();
this.el.style.cssText = `
position: absolute;
left: ${l}; top: ${t};
transform-style: preserve-3d;
`;
}
add(face) {
if (!(face instanceof Face)) throw "invalid face";
this.el.appendChild(face.el);
return face;
}
};
const mesh = new Mesh("50%", "50%");
const r = 100,
height = 196,
sides = 20;
const sideAngle = (Math.PI / sides) * 2;
const sideLen = r * Math.tan(Math.PI / sides);
for (let c = 0; c < sides; c++) {
const x = (Math.sin(sideAngle * c) * r) / 2;
const z = (Math.cos(sideAngle * c) * r) / 2;
const ry = Math.atan2(x, z);
const face = new Face(sideLen + 1, height, x, 0, z, 0, ry, 0, sideLen * c, 0);
face.class = "drum";
mesh.add(face);
}
const tface = new Face(100, 100, 0, -98, 0, Math.PI / 2, 0, 0, 0, 100);
const bface = new Face(100, 100, 0, 98, 0, -Math.PI / 2, 0, 0, 0, 100);
tface.class = "drum";
bface.class = "drum";
mesh.add(tface);
mesh.add(bface);
mesh.class = "ani";
document.body.appendChild(mesh.el);
</script>
</html>
이유 : 만약 Math.PI로 부여한다면 마치 한쪽은 열려있는 것으로 보이나 실제로는 둘 다 막혀 있다.
단지,backface-visibility: hidden;
에 의해 우리가 보는 구멍이 안보이는 상태이기 때문이다.
일단 사진 기준으로 봤을때 right는 +, top은 +이다.
이를 기준으로 ty가 100이라는 것은 위로 100만큼 위치한 부분을 기준을 잡는다는 것이다.
기존 사진에서 위로 100만큼 가면 다시 사진의 원통의 시작부분이기 때문에 ty를 100으로 잡았다.
정리하자면 ty를 -196으로 부여해도 같은 결과가 나온다.
왜냐하면 위로 100 올린것은 다른의미로 직사각형 형태부분인 196을 넘어서 원형형태부분의 시작점과 같기 때문이다.
w,h : 사진부분의 높이 넓이 => 이를 추후에 중앙을 맞춘다.
x,y,z : 만들어진 부분에서부터 떨어진 거리 => 모아진 형태들을 넓게 퍼트릴 수 있다.
rx,ry,rz : 만들어진 것들의 회전 => 만들어진 것의 회전을 부여하여 원하는 회전 결과를 만들어낸다.
tx,ty : 2차원 사진을 기준으로 점이 시작하는 위치 => 2차원이므로 top, right가 +가 된다.