Three.js实现O/X变换
一.HTML部分
#scene
#world
二.CSS部分
body {
display:flex;
min-height:100vh;
justify-content:center;
align-items:center;
overflow:hidden;
}
#scene {
perspective:1000px;
animation:g 2.5s infinite alternate;
} @keyframes g {
from, to {perspective:60000px}
25%, 75% {perspective:600px;}
}
#world {
animation:f 5s infinite alternate;
} @keyframes f {
from, 20% {transform:rotateY(0deg)}
30%, 70% {transform:rotateY(-90deg)}
80%, to {transform:rotateY(-180deg)}
}
三.JS部分
scene.setAttribute("style",`
width:50vw;
height:50vh;
transform-style:preserve-3d;
position:relative;
`);
world.setAttribute("style", `
width:100%;
height:100%;
transform-style:preserve-3d;
position:relative;
perspective-origin:center center 0;
`)
function add(x, y, z, wx, wy, ry) {
const el = document.createElement("div");
el.setAttribute("style", `
width:${wx}px;
height:${wy}px;
background:rgba(0,0,0,0.2);
position:absolute;
left:${x}px;
top:${y}px;
transform:translate3d(-50%,-50%,${z}px)rotateY(${ry}rad);
transform-style:preserve-3d;
`);
world.appendChild(el);
return el;
}
{
const wx = 10;
const wy = 10;
const depth = 150;
const N = 40;
const {cx, cy} = centerOf(world);
const r = Math.min(cx, cy);
for (let i=0; i<N; i++) {
const an = i/N*Math.PI*2
const x = Math.cos(an) * r + cx;
const y = Math.sin(an) * r + cy;
const ry = -an + Math.PI/2;
let z;
// deg c d
// a 0~90 \ /
// b 90~180 z+__\ /
// c 180~270 /|\
// d 270~360 / | \
// b y+ a
if (an < Math.PI/2) {
z = remap(an, 0, Math.PI/2, 0, depth);
}
else if (an < Math.PI) {
z = remap(an, Math.PI/2, Math.PI, -depth, 0);
}
else if (an < Math.PI * 3/2) {
z = remap(an, Math.PI, Math.PI*3/2, 0, -depth);
}
else if (an < Math.PI * 2) {
z = remap(an, Math.PI*3/2, Math.PI*2, depth, 0);
}
add(x, y, z, wx, wy, ry);
}
const ref = add(cx,cy+r,0,r*2,depth*2,0);
ref.style.transform = `
translate(-50%, -50%)
rotateX(90deg)
`;
}
function remap(x, min, max, a, b) {
return a + (b-a) * (x-min)/(max-min);
}
function centerOf(el) {
const {width, height} = el.getBoundingClientRect();
return {cx:width/2, cy:height/2};
}