Bootstrap

Three.js实现O/X变换

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};
}

;