[three.js] ページ開き (1)

three.jsを使って、ページを開くのを作ってみちゃうよ。 :boy:

threejs_book1

index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1.0">
<title>ページ開き (1) | three.js</title>
<script src="js/three.min.js"></script>
<script src="js/detector.js"></script>
<script src="js/stats.min.js"></script>
<style type="text/css">
  html { overflow:hidden; }
  body { margin:0; padding:0; }
</style>
</head>
<body style="background-color:#EEEEEE">
<script>
var scene, camera, renderer, stats;
var book, sheet, container, papers, current;
var angle = 0;
var speed = 5;
var id = 0;
var opening = false;
var opened = false;
var vector = new THREE.Vector3();
var direction = new THREE.Vector3();
var limit = 0.1;
var radius = 500;
var radian = Math.PI/180;
var center = new THREE.Object3D();

window.onload = init;

function init() {
  if (!Detector.webgl) Detector.addGetWebGLMessage();

  scene = new THREE.Scene();
  camera = new THREE.PerspectiveCamera(60, window.innerWidth/window.innerHeight, 0.1, 2000);
  scene.add(camera);
  renderer = new THREE.WebGLRenderer({antialias: true});
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);
  setup();
  initialize();
  window.addEventListener("click", click, false);
  document.addEventListener("touchstart", touch, false);

  stats = new Stats();
  stats.setMode(0);
  stats.domElement.style.position = "fixed";
  stats.domElement.style.right = "0px";
  stats.domElement.style.top = "0px";
  document.body.appendChild(stats.domElement);

  render();
  window.addEventListener("resize", resize, false);
}
function setup() {
  renderer.setClearColor(0xEEEEEE, 1);
  camera.position.z = -radius;
  camera.lookAt(center.position);
}
function initialize() {
  book = new THREE.Group();
  scene.add(book);
  book.position.z = 500;
  var geometry = new THREE.PlaneGeometry(200, 250);
  var material = new THREE.MeshBasicMaterial({side: THREE.BackSide, color: 0x666666});
  sheet = new THREE.Mesh(geometry, material);
  book.add(sheet);
  sheet.position.x = 400;
  container = new THREE.Group();
  book.add(container);
  container.position.x = 300;
  var paper1 = createPaper(0x333399, 0x3399CC);
  container.add(paper1);
  var paper2 = createPaper(0x669900, 0x99CC00);
  paper1.children[2].add(paper2);
  paper2.position.x = - 100;
  var paper3 = createPaper(0xFF9900, 0xFFCC00);
  paper2.children[2].add(paper3);
  paper3.position.x = - 100;
  var paper4 = createPaper(0xCC0066, 0xFF6699);
  paper3.children[2].add(paper4);
  paper4.position.x = - 100;
  papers = [paper1, paper2, paper3, paper4];
}
function createPaper(bc, fc) {
  var paper = new THREE.Group();
  var geometry = new THREE.PlaneGeometry(200, 250);
  var bmaterial = new THREE.MeshBasicMaterial({side: THREE.BackSide, color: bc});
  bmaterial.depthTest = false;
  var fmaterial = new THREE.MeshBasicMaterial({side: THREE.FrontSide, color: fc});
  fmaterial.depthTest = false;
  var back = new THREE.Mesh(geometry, bmaterial);
  paper.add(back);
  back.position.x = 100;
  var front = new THREE.Mesh(geometry, fmaterial);
  paper.add(front);
  front.position.x = 100;
  var child = new THREE.Group();
  paper.add(child);
  child.rotation.y = 180*radian;
  child.position.x = 100;
  child.visible = false;
  return paper;
}
function click(event) {
  start();
}
function touch(event) {
  start();
}
function start() {
  if (!this.opened) {
    open();
  } else {
    close();
  }
  current = papers[id];
  setaxis();
}
function open() {
  opening = true;
}
function update() {
  if (angle < 180) {
    angle += speed;
    current.rotation.y = angle*radian;
    if (face()) {
      current.children[2].visible = true;
    }
  } else {
    if (id < 3) {
      angle = 0;
      id ++;
      current = papers[id];
      setaxis();
    } else {
      opening = false;
      opened = true;
    }
  }
}
function close() {
  opened = false;
  angle = 0;
  id = 0;
  for (var n = 0; n < 4; n++) {
    var paper = papers[n];
    paper.rotation.y = 0;
    paper.children[2].visible = false;
  }
}
function setaxis() {
  var axis = new THREE.Vector3(300 - 200*id, 0, 500);
  direction.subVectors(axis, camera.position);
}
function face() {
  var vx = - Math.cos(angle*radian);
  var vy = 0;
  var vz = Math.sin(angle*radian);
  vector.set(vx, vy, vz);
  var dx = direction.x;
  var dy = direction.y;
  var dz = direction.z;
  var product = vx*dx + vy*dy + vz*dz;
  var length = vector.length()*direction.length();
  return Math.acos(product/length) < limit;
}
function render() {
  requestAnimationFrame(render);

  if (opening) update();

  renderer.render(scene, camera);

  stats.update();
}
function resize(event) {
  camera.aspect = window.innerWidth/window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
}
</script>
</body>
</html>


[修正] (14/12/27 Sat 21:25)
HTML記述を変更。